/*
 * Copyright 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cofluent.web.client.widget;

import com.cofluent.web.client.model.Build;
import com.cofluent.web.client.provider.DynaTableDataProvider;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Widget;

/**
 * A composite Widget that implements the main interface for the dynamic table,
 * including the data table, status indicators, and paging buttons.
 */
public class DynaTableWidget extends Composite {
	private class NavBar extends Composite implements ClickListener {

		public final DockPanel bar = new DockPanel();

		public final Button gotoFirst = new Button("&lt;&lt;", this);

		public final Button gotoNext = new Button("&gt;", this);

		public final Button gotoPrev = new Button("&lt;", this);

		public final HTML status = new HTML();

		public NavBar() {
			initWidget(bar);
			bar.setStyleName("navbar");
			status.setStyleName("status");

			HorizontalPanel buttons = new HorizontalPanel();
			buttons.add(gotoFirst);
			buttons.add(gotoPrev);
			buttons.add(gotoNext);
			bar.add(buttons, DockPanel.EAST);
			bar.setCellHorizontalAlignment(buttons, DockPanel.ALIGN_RIGHT);
			bar.add(status, DockPanel.CENTER);
			bar.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
			bar.setCellHorizontalAlignment(status, HasAlignment.ALIGN_RIGHT);
			bar.setCellVerticalAlignment(status, HasAlignment.ALIGN_MIDDLE);
			bar.setCellWidth(status, "100%");

			// Initialize prev & first button to disabled.
			//
			gotoPrev.setEnabled(false);
			gotoFirst.setEnabled(false);
		}

		public void onClick(Widget sender) {
			if (sender == gotoNext) {
				startRow += getDataRowCount();
				refresh();
			} else if (sender == gotoPrev) {
				startRow -= getDataRowCount();
				if (startRow < 0) {
					startRow = 0;
				}
				refresh();
			} else if (sender == gotoFirst) {
				startRow = 0;
				refresh();
			}
		}
	}
	
	private class DeleteListener implements ClickListener
	{
		private YesNoDialogBox dialogBox;
		private final Build build;

		public DeleteListener(Build build)
		{
			this.build=build;
			dialogBox=new YesNoDialogBox("Are you sure ?");
			dialogBox.getYesButton().addClickListener(this);
		}

		public void onClick(Widget widget)
		{
			if(widget==dialogBox.getYesButton())
			{
				provider.delete(build, new AsyncCallback () {
					public void onFailure(Throwable t)
					{
						t.printStackTrace();
						setStatusText("Failed deleting the build: " + t.getMessage());
					}
					public void onSuccess(Object obj)
					{
						setStatusText("Build deleted successfully");
						provider.reload(new AsyncCallback() {
							public void onFailure(Throwable t)
							{
								t.printStackTrace();
								setStatusText("Failed refreshing: " + t.getMessage());
							}
							public void onSuccess(Object arg0)
							{
								refresh();
							}
						});
					}
				});
			}
			else if (widget instanceof Button)
			{
				Button deleteButton=(Button)widget;
				dialogBox.show();
				dialogBox.setPopupPosition(deleteButton.getAbsoluteLeft(),
						deleteButton.getAbsoluteTop()+deleteButton.getOffsetHeight());
//				dialogBox.center();
			}
		}
	}

	private class AsyncCallbackImpl implements AsyncCallback {
		public void onSuccess(Object result) {
			Build[] builds = (Build[]) result;
//			ArrayList list=new ArrayList(); 
//			for (int i = 0; i < builds.length; i++) {
//				Build build = builds[i];
//				if(filter==null || filter.accept(build))
//					list.add(build);
//			}
//			lastStartRow = startRow;
//			lastMaxRows = maxRows;
//			lastPeople = people;
//			builds=new Build[list.size()];
//			int i=0;
//			for (Iterator iter = list.iterator(); iter.hasNext();) {
//				Build build = (Build) iter.next();
//				builds[i++]=build;
//			}
//			lastBuilds=builds;
			pushResults(/*acceptor,*/ builds);
		}

		private void pushResults(//RowDataAcceptor acceptor, //int startRow, int maxRows,
				Build[] builds) {
			String[][] rows = new String[builds.length][];
			for (int i = 0, n = rows.length; i < n; i++) {
				Build build = builds[i];
				rows[i]=build.toStringArray();/*new String[4]*/;
//				rows[i][0] = build.getCvsTag();
//				rows[i][1] = build.getVersionNumber();
//				rows[i][2] = build.getBuildNumber();
//				rows[i][3] = build.getReleaseNumber();
			}
			/*acceptor.*/accept(builds,/*startRow, maxRows,*/ rows);
		}

		public void accept(Build [] builds,/*int startRow, int maxRows,*/ String[][] data) {

			int destRowCount = getDataRowCount();
			int destColCount = grid.getCellCount(0)-1;
			assert (data.length <= destRowCount) : "Too many rows";
			assert (visibleColumns.length != destColCount) : "Visible columns invalid size" ;

			int srcRowIndex = 0;
			int srcRowCount = data.length;
			int destRowIndex = 1; // skip navbar row
			for (; srcRowIndex < srcRowCount; ++srcRowIndex, ++destRowIndex) {
				String[] srcRowData = data[srcRowIndex];
				Build build=builds[srcRowIndex];
				assert (srcRowData.length == destColCount) : " Column count mismatch";
				for (int srcColIndex = 0; srcColIndex < destColCount; ++srcColIndex) {
					String cellHTML = srcRowData[srcColIndex];
					if(visibleColumns[srcColIndex])
						grid.setText(destRowIndex, srcColIndex, cellHTML);
				}
				Button deleteButton=new Button("Delete");
				deleteButton.addClickListener(new DeleteListener (build));
				grid.setWidget(destRowIndex, destColCount, deleteButton);
			}

			// Clear remaining table rows.
			//
			boolean isLastPage = false;
			for (; destRowIndex < destRowCount + 1; ++destRowIndex) {
				isLastPage = true;
				for (int destColIndex = 0; destColIndex < destColCount; ++destColIndex) {
					grid.clearCell(destRowIndex, destColIndex);
				}
				grid.clearCell(destRowIndex, destColCount);
			}

			// Synchronize the nav buttons.
			//
			navbar.gotoNext.setEnabled(!isLastPage);
			navbar.gotoFirst.setEnabled(startRow > 0);
			navbar.gotoPrev.setEnabled(startRow > 0);

			// Update the status message.
			//
			setStatusText((startRow + 1) + " - " + (startRow + srcRowCount));
		}

		public void onFailure(Throwable caught) {
			String msg = "Failed to access data";
			if (caught != null) {
				msg += ": " + caught.getMessage();
			}
			setStatusText(msg);
		}
	}

//	private final RowDataAcceptor acceptor = new RowDataAcceptorImpl();
	private final AsyncCallback asyncCallback=new AsyncCallbackImpl();

	private final NavBar navbar = new NavBar();

	private final DockPanel outer = new DockPanel();

	private final DynaTableDataProvider provider;

	private int startRow = 0;

	private final Grid grid = new Grid();

	private boolean[] visibleColumns;

	public DynaTableWidget(DynaTableDataProvider provider, String[] columns,
			String[] columnStyles, boolean[] visibleColumns, int rowCount)
	{
		this.visibleColumns=visibleColumns;
		
		if (columns.length == 0) {
			throw new IllegalArgumentException(
					"expecting a positive number of columns");
		}

		if (columnStyles != null && columns.length != columnStyles.length) {
			throw new IllegalArgumentException(
					"expecting as many styles as columns");
		}

		this.provider = provider;
		initWidget(outer);
		grid.setStyleName("table");
		outer.add(navbar, DockPanel.NORTH);
		outer.add(grid, DockPanel.CENTER);
		initTable(columns, columnStyles, rowCount);
		setStyleName("DynaTable-DynaTableWidget");
		refresh();
	}

	public void clearStatusText() {
		navbar.status.setHTML("&nbsp;");
	}

	public void refresh() {
		// Disable buttons temporarily to stop the user from running off the end.
		//
		navbar.gotoFirst.setEnabled(false);
		navbar.gotoPrev.setEnabled(false);
		navbar.gotoNext.setEnabled(false);

		setStatusText("Please wait...");
		provider.updateRowData(/*startRow, grid.getRowCount() - 1,*/ asyncCallback);
	}

	public void setRowCount(int rows) {
		grid.resizeRows(rows);
	}

	public void setStatusText(String text) {
		navbar.status.setText(text);
	}

	int getDataRowCount() {
		return grid.getRowCount() - 1;
	}

	private void initTable(String[] columns, String[] columnStyles, int rowCount) {
		// Set up the header row. It's one greater than the number of visible rows.
		//
		grid.resize(rowCount + 1, columns.length + 1);
		for (int i = 0, n = columns.length; i < n; i++)
		{
			if (visibleColumns[i])
			{
				Hyperlink hyperlink=new Hyperlink(columns[i], columns[i]);
				hyperlink.addClickListener(new ClickListener() {
					public void onClick(Widget sender) {
						Hyperlink hyperlink=(Hyperlink) sender;
						sort(hyperlink.getText());
					}
				});
//				grid.setText(0, i, columns[i]);
				grid.setWidget(0, i, hyperlink);
				if (columnStyles != null) {
					grid.getCellFormatter().setStyleName(0, i,
							columnStyles[i] + " header");
				}
			}
		}
	}

	private void sort(String columnName) {
		System.out.println("DynaTableWidget.sort() " + columnName);
	}
}
